public with sharing class EnquiryController 
{
    public static final String FRANCHISE_PARAM = 'franchise';
    
    public static final String HEADING_TEXT_PARAM = 'headingtext';
    
    public static final String BACKGROUND_COLOUR_PARAM = 'bgcolour';
    
    public static final String TEXT_COLOUR_PARAM = 'textcolour';
    
    private static final String FROM_EMAIL_ADDRESS = 'leads@franchiseselect.com.au';
    
    public static final String DEFAULT_POSTCODE = 'postcode...';
    
    public static final String DEFAULT_SUBURB = 'suburb...';
    
    private ContactDetails contactDetails = new ContactDetails();
    
    public String headingText {get;set;}
    
    public String backGroundColour {get;set;}
    
    public String textColour {get;set;}
    
    public boolean submitted {get;set;}
    
    public EnquiryController()
    {
        String franchiseNumber = Apexpages.currentPage().getParameters().get(FRANCHISE_PARAM);
        if(!CommonUtils.isBlank(franchiseNumber))
        {
            Account franchise = getFranchiseByFranchiseNum(franchiseNumber);
            if(franchise != null)
            {
                this.contactDetails.franchiseOfInterest = franchise.id;
            }
            else
            {
                System.debug('Invalid franchise number ' + franchiseNumber);
            }
        }
        //Set form specific styling attributes
        headingText = Apexpages.currentPage().getParameters().get(HEADING_TEXT_PARAM);
        backGroundColour = Apexpages.currentPage().getParameters().get(BACKGROUND_COLOUR_PARAM);
        textColour = Apexpages.currentPage().getParameters().get(TEXT_COLOUR_PARAM);
        contactDetails.franchiseWebSource = franchiseNumber;
        submitted = false;
    }
    
    public ContactDetails getContactDetails()
    {
        return this.contactDetails;
    }
    
    public PageReference eventSubmitGeneralEnquiry()
    {
        return submitEnquiry('Franchise application', 'enquiryResponse');
    }
    
    public PageReference eventSubmitPrePurchaseEnquiry()
    {   try
        {
            //Grab the default franchise account and set the id
            //to the Contact Details record - there should only ever be one account
            //marked as default.
            Account defaultFranchise = [Select id, name from Account where default__c = true limit 1];
            if(defaultFranchise != null)
            {
                this.contactDetails.franchiseOfInterest = defaultFranchise.id;
            }
        }
        catch(System.Exception e)
        {
            System.debug('Issue retrieving default franchise ' + e.getMessage());
            return null;
        }
        return submitEnquiry('Pre purchase advice', 'enquiryResponse');
    }
    
    private PageReference submitEnquiry(String oppName, String emailTemplate)
    {
        validateGeneralEnquiry();
        if(this.contactDetails.getHasValidationErrors())
        {
             return null;
        }
        try
        {
            Account account;
            Account franchiseAccount = getFranchise(this.contactDetails.franchiseOfInterest);
            RecordType recordType = getRecordType('Candidate', true);  
            if(!isRegistered(this.contactDetails.email))
            {
                account = new Account(); 
                account.Date_of_Account_Commencement__c = System.today();
                account.PersonEmail = this.contactDetails.email;
                //Now we have to assign the appropriate owner 
                setObjectOwnerId(account);
            }
            else
            {
                account = 
                    [Select id from Account where RecordTypeId = :recordType.id and PersonEmail = :this.contactDetails.email and IsPersonAccount = true LIMIT 1]; 
            }
            account.FirstName = this.contactDetails.firstName;
            account.LastName = this.contactDetails.surname;
            account.Phone = this.contactDetails.phone;
            account.PersonMobilePhone = this.contactDetails.mobile;
            account.BillingPostalCode = this.contactDetails.postcode;
            account.BillingState = this.contactDetails.state;
            account.Budget__c = this.contactDetails.budget;
            account.purchaseTimeframe__c = this.contactDetails.purchaseTimeframe;
	            account.Desired_Location__c = this.contactDetails.desiredSuburb;
            account.Location_of_Interest__c = this.contactDetails.desiredState;
            account.contactBusinessHours__c = this.contactDetails.contactDuringBusinessHours;
            account.candidateLeadsource__c = this.contactDetails.candidateLeadSource;
            account.Lead_Source__c = this.contactDetails.whereDidYouHear;
            account.candidateActivityStatus__c = 'Active';
            //Only update the industry of interest we are not assigning this to the default
            //franchise
            if(!franchiseAccount.default__c)
            {
                account.Industry_of_Interest__c = franchiseAccount.Industry_of_Interest__c;
            }
            upsert account;
            //Now load account again as we need the regardless of whether we just inserted a new account ContactID 
            account = 
                [Select id, Name, Budget__c from Account where RecordTypeId = :recordType.id and PersonEmail = :this.contactDetails.email and IsPersonAccount = true LIMIT 1]; 
            Opportunity franchiseApplication = new Opportunity();
            franchiseApplication.AccountId = account.id;
            franchiseApplication.CloseDate = System.today() + (365 * 2);
            franchiseApplication.Contacted__c = false;
            if(CommonUtils.isNotBlank(this.contactDetails.franchiseOfInterestFreeText))
            {            
                franchiseApplication.Description = this.contactDetails.franchiseOfInterestFreeText;
            }    
            franchiseApplication.franchisorAccount__c = franchiseAccount.id;
            franchiseApplication.name = oppName;
            franchiseApplication.StageName = 'Not Contacted';
            insert franchiseApplication;
            //Now send to all the contacts associated with the default franchise select record
            //This is to send it to internal employees of refunds select
            Account defaultAccount = [Select id, name from Account where default__c = true limit 1];
            if(defaultAccount != null)
            {
                List<Contact> contacts = [Select id, name, email from Contact where account.id = :defaultAccount.id and leadContact__c = true];
                if(contacts != null)
                {
                    for(Contact contact : contacts)
                    {
                        sendEmail(contact, emailTemplate, franchiseApplication.id);
                    }
                }
            }
            //Now we need to send it to the franchise if we're not creating a pre purchase enquiry
            //thus the franchise account won't be set as default as all pre-purchase enquiries are
            //related to the default franchise select account.
            if(!franchiseAccount.default__c)
            {
                List<Contact> contacts = [Select id, name, email from Contact where account.id = :franchiseAccount.id and leadContact__c = true];
                if(contacts != null)
                {
                    
                    for(Contact contact : contacts)
                    {
                        sendEmail(contact, emailTemplate, franchiseApplication.id);
                    }
                    
                }
            }
            submitted = true;
            return null;
        }
        catch(System.Exception e)
        {
            System.debug(e.getMessage());
            return null;
        }   
    }
    
    public void validateGeneralEnquiry()
    {
        this.contactDetails.errors = new Set<String>();
        if(CommonUtils.isBlank(this.contactDetails.firstName))
        {
            this.contactDetails.errors.add('firstName');
        }
        if(CommonUtils.isBlank(this.contactDetails.surname))
        {
            this.contactDetails.errors.add('surname');
        }
        if(CommonUtils.isBlank(this.contactDetails.franchiseOfInterest))
        {
            this.contactDetails.errors.add('franchiseOfInterest');
        }
        if(CommonUtils.isBlank(this.contactDetails.email))
        {
            this.contactDetails.errors.add('email');
        }
        if(CommonUtils.isBlank(this.contactDetails.confirmEmail) || 
            !(this.contactDetails.confirmEmail.equals(this.contactDetails.email)))
        {
            this.contactDetails.errors.add('confirmEmail');
        }
        if(CommonUtils.isBlank(this.contactDetails.phone))
        {
            this.contactDetails.errors.add('phone');
        }
        if(CommonUtils.isBlank(this.contactDetails.mobile))
        {
            this.contactDetails.errors.add('mobile');
        }
        if(CommonUtils.isBlank(this.contactDetails.postcode) || 
            this.contactDetails.postcode.equals(DEFAULT_POSTCODE))
        {
            this.contactDetails.errors.add('postcode');
        }
        if(CommonUtils.isBlank(this.contactDetails.state))
        {
            this.contactDetails.errors.add('state');
        }
        if(CommonUtils.isBlank(this.contactDetails.budget))
        {
            this.contactDetails.errors.add('budget');
        }
        if(CommonUtils.isBlank(this.contactDetails.purchaseTimeframe))
        {
            this.contactDetails.errors.add('purchaseTimeframe');
        }
        if(CommonUtils.isBlank(this.contactDetails.desiredSuburb) || 
            this.contactDetails.desiredSuburb.equals(DEFAULT_SUBURB))
        {
            this.contactDetails.errors.add('desiredSuburb');
        }
        if(CommonUtils.isBlank(this.contactDetails.desiredState))
        {
            this.contactDetails.errors.add('desiredState');
        }
        if(CommonUtils.isBlank(this.contactDetails.contactDuringBusinessHours))
        {
            this.contactDetails.errors.add('contactDuringBusinessHours');
        }
        if(CommonUtils.isBlank(this.contactDetails.whereDidYouHear))
        {
            this.contactDetails.errors.add('whereDidYouHear');
        }
        if(CommonUtils.isBlank(this.contactDetails.candidateLeadSource))
        {
            this.contactDetails.errors.add('candidateLeadSource');
        }
        if(!contactDetails.termsAndConditionsAccepted)
        {
            this.contactDetails.errors.add('termsAndConditionsAccepted');
        }
    }
    
    public RecordType getRecordType(String recordTypeName, Boolean isPersonAccount)
    {
        RecordType recordType = null;
        try
        {
            recordType = 
                [Select Id, Name From RecordType Where SobjectType = 'Account' and Name = :recordTypeName AND IsPersonType=:isPersonAccount LIMIT 1];
            System.debug('Record Type --> '  + recordType.Name);
        }
        catch(Exception e)
        {
            System.debug(e.getMessage());
        }
        return recordType;
         
    }
    
    public boolean isRegistered(String email)
    {
        try
        {
            RecordType recordType = getRecordType('Candidate', true);
            Account account = 
                [Select id from Account where RecordTypeId = :recordType.id and PersonEmail = :email and IsPersonAccount = true LIMIT 1];
            return true;
        }
        catch(Exception e)
        {
            System.debug(e.getMessage());
            return false;
        }
    }
    
    public Account getFranchise(String id)
    {
        
        Account franchise = null;
        if(id != null)
        {
            try
            {
                RecordType recordType = getRecordType('Franchisor', false);
                franchise = [select id, name, Industry_of_Interest__c, default__c from Account where account.RecordTypeId = :recordType.id and id = :id LIMIT 1];
            }
            catch(System.Exception e)
            {
              System.debug(e.getMessage());
            }
        }
        return franchise;
    }
    
    /**
    * Try and get the appropriate parent account based on the refferer code.  If none exists or the refferrer code
    * is null then we don't set the parent account meaning it's a refund direct customer.
    */
    private void setObjectOwnerId(SObject objectReference)
    {
        try
        {
            String likePredicate = '%' + this.contactDetails.state + '%';
            //This statement will retrieve the least recently used user and assign their id as owner to the new account
            User user = [Select id from User where statesServiced__c like :likePredicate and IsActive = true  order by lastAllocatedDate__c asc limit 1];
            objectReference.put('OwnerId', user.id);
            user.lastAllocatedDate__c = System.now();
            update user;
        
        }
        catch(System.Exception e)
        {
            System.debug(e.getMessage());
        }  
    }
    
    public List<SelectOption> getFranchiseOfInterest()
    {
        RecordType recordType = getRecordType('Franchisor', false);
        List<Account> franchises = [Select id, name from Account where account.RecordTypeId = :recordType.id and franchisorStatus__c = 'FS Client' order by name asc];    
        List<SelectOption> options = new List<SelectOption>();
        options.add(new SelectOption('', 'Please select.....'));
        for(Account franchise : franchises)
        {
           options.add(new SelectOption(franchise.id, franchise.name));
        }       
        return options;
    }
    
    public List<SelectOption> getStates()
    {
        List<SelectOption> options = new List<SelectOption>();
        Schema.DescribeFieldResult fieldResult =
                 Account.state__c.getDescribe();
        List<Schema.PicklistEntry> picklistEntries = fieldResult.getPicklistValues();    
        options.add(new SelectOption('', 'State.....'));
        for( Schema.PicklistEntry pickListEntry : picklistEntries)
        {
           options.add(new SelectOption(pickListEntry.getValue(), pickListEntry.getValue()));
        }       
        return options;
    }
    
    public List<SelectOption> getDesiredLocationStates()
    {
        List<SelectOption> options = new List<SelectOption>();
        Schema.DescribeFieldResult fieldResult =
                 Account.Location_of_Interest__c.getDescribe();
        List<Schema.PicklistEntry> picklistEntries = fieldResult.getPicklistValues();    
        options.add(new SelectOption('', 'State.....'));
        for( Schema.PicklistEntry pickListEntry : picklistEntries)
        {
           options.add(new SelectOption(pickListEntry.getValue(), pickListEntry.getValue()));
        }       
        return options;
    }
    
    
    
    public List<SelectOption> getBudgets()
    {
        List<SelectOption> options = new List<SelectOption>();
        Schema.DescribeFieldResult fieldResult =
                 Account.budget__c.getDescribe();
        List<Schema.PicklistEntry> picklistEntries = fieldResult.getPicklistValues();    
        options.add(new SelectOption('', 'Please select.....'));
        for( Schema.PicklistEntry pickListEntry : picklistEntries)
        {
           options.add(new SelectOption(pickListEntry.getValue(), pickListEntry.getValue()));
        }       
        return options;
    }
    
    public List<SelectOption> getTimeframes()
    {
        List<SelectOption> options = new List<SelectOption>();
        Schema.DescribeFieldResult fieldResult =
                 Account.purchaseTimeframe__c.getDescribe();
        List<Schema.PicklistEntry> picklistEntries = fieldResult.getPicklistValues();    
        options.add(new SelectOption('', 'Please select.....'));
        for( Schema.PicklistEntry pickListEntry : picklistEntries)
        {
           options.add(new SelectOption(pickListEntry.getValue(), pickListEntry.getValue()));
        }       
        return options;
    }
    
    public List<SelectOption> getCandidateLeadSource()
    {
        List<SelectOption> options = new List<SelectOption>();
        Schema.DescribeFieldResult fieldResult =
                 Account.candidateLeadsource__c.getDescribe();
        List<Schema.PicklistEntry> picklistEntries = fieldResult.getPicklistValues();    
        options.add(new SelectOption('', 'Please select.....'));
        for( Schema.PicklistEntry pickListEntry : picklistEntries)
        {
           options.add(new SelectOption(pickListEntry.getValue(), pickListEntry.getValue()));
        }       
        return options;
    }
    
    public List<SelectOption> getLeadSource()
    {
        List<SelectOption> options = new List<SelectOption>();
        Schema.DescribeFieldResult fieldResult =
                 Account.Lead_Source__c.getDescribe();
        List<Schema.PicklistEntry> picklistEntries = fieldResult.getPicklistValues();    
        options.add(new SelectOption('', 'Please select.....'));
        for( Schema.PicklistEntry pickListEntry : picklistEntries)
        {
           options.add(new SelectOption(pickListEntry.getValue(), pickListEntry.getValue()));
        }       
        return options;
    }
    
    private Account getFranchiseByFranchiseNum(String franchiseNumber)
    {
        Account franchise = null;
        try
        {
            RecordType recordType = getRecordType('Franchisor', false);
            franchise = [select id, name from Account where account.RecordTypeId = 
                :recordType.id and franchiseNumber__c = :franchiseNumber and franchisorStatus__c = 'FS Client' LIMIT 1];
        }
        catch(System.Exception e)
        {
          System.debug(e.getMessage());
        }
        return franchise;
    }
    
    /**
    * Sends out the email to the appropriate email address using the passed in template
    */
    private void sendEmail(Contact contact, String emailTemplateName, Id whatId)
    {
        try
        {
            System.debug('Template name: ' + emailTemplateName);
            Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage ();
            EmailTemplate et = [SELECT id FROM EmailTemplate WHERE DeveloperName = :emailTemplateName];
            mail.setSenderDisplayName('Franchise Select');
            mail.setTargetObjectId(contact.id);
            mail.setSenderDisplayName(FROM_EMAIL_ADDRESS);
            mail.setReplyTo(FROM_EMAIL_ADDRESS);
            //mail.setTargetObjectId(saveRequest.id); // Specify who the email should be sent to.
            mail.setTemplateId(et.id);
            mail.setWhatId(whatId);
            Messaging.sendEmail(new Messaging.SingleEmailMessage [] { mail });
        }
        catch(System.Exception e)
        {
            System.debug('Could not send email to: ' + contact.email + ' --> ' + e.getMessage());
        }
    }
    
    static testMethod void testThis()
    {
        EnquiryController enquiryController = new EnquiryController();
        List<SelectOption> options = enquiryController.getFranchiseOfInterest();
        System.debug(options.size());
        System.assert(options.size() > 0);
        for(SelectOption option : options)
        {
            System.debug(option.getValue());
            System.debug(option.getLabel());
            
        }
        enquiryController.getCandidateLeadSource();
        enquiryController.getTimeframes();
        enquiryController.getBudgets();
        enquiryController.getStates();
        enquiryController.getLeadSource();
        enquiryController.getCandidateLeadSource();
        Account account = new Account();
        account.Name = 'Test123';
        account.franchisorStatus__c = 'FS Client';
        insert account;
        account = [Select id, franchiseNumber__c from Account where name = 'Test123'];
        enquiryController.getFranchiseByFranchiseNum(account.franchiseNumber__c);
        enquiryController.getFranchise(account.id);
    }
    
    /*
    static testMethod void testSetOwnerId()
    {
        EnquiryController enquiryController = new EnquiryController();
        enquiryController.contactDetails.state = 'WA';
        Account account = new Account();
        account.name = 'Test Account';
        enquiryController.setObjectOwnerId(account);
        User user1 = [Select id, name from User where id = :account.OwnerId];
        System.debug(user1.name);
        System.assert(user1.id == account.OwnerId);
        enquiryController.setObjectOwnerId(account);
        User user2 = [Select id, name from User where id = :account.OwnerId];
        System.debug(user2.name);
        System.assert(user2.id == account.OwnerId);
        System.assert(user1.id != user2.id);
    }
    */
    
    static testMethod void testEventSubmitGeneralEnquiry()
    {
        EnquiryController enquiryController = new EnquiryController();
        enquiryController.contactDetails.firstName = 'Test';
        enquiryController.contactDetails.surname = 'User';
        enquiryController.contactDetails.franchiseWebSource = 'Test';
        enquiryController.contactDetails.franchiseOfInterest = 'Test'; 
        enquiryController.contactDetails.firstName = 'Test';
        enquiryController.contactDetails.surname = 'Test';
        enquiryController.contactDetails.email = 'Test@Test.com';
        enquiryController.contactDetails.confirmEmail = 'Test';
        enquiryController.contactDetails.phone = 'Test';
        enquiryController.contactDetails.mobile = 'Test';
        enquiryController.contactDetails.postcode = 'Test';
        enquiryController.contactDetails.state = 'Test';
        enquiryController.contactDetails.budget = 'Test';
        enquiryController.contactDetails.purchaseTimeframe = 'Test';
        enquiryController.contactDetails.desiredSuburb = 'Test';
        enquiryController.contactDetails.desiredState = 'Test';
        enquiryController.contactDetails.contactDuringBusinessHours = 'Test';
        enquiryController.contactDetails.whereDidYouHear = 'Test';
        enquiryController.contactDetails.candidateLeadSource = 'Test';
        enquiryController.contactDetails.termsAndConditionsAccepted = true;
        enquiryController.validateGeneralEnquiry();
        System.assert(enquiryController.contactDetails.getHasValidationErrors());
        System.assert(enquiryController.contactDetails.getConfirmEmailError());
        enquiryController.contactDetails.confirmEmail = 'Test@Test.com';
        enquiryController.eventSubmitGeneralEnquiry();
        enquiryController.eventSubmitPrePurchaseEnquiry();
        System.assert(!enquiryController.contactDetails.getHasValidationErrors());
        enquiryController.getContactDetails();
       
    }
  

}